﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Text;
using EnvDTE;

namespace Highlighterr
{

    [Export(typeof(IClassifierProvider))]
    [ContentType("Text")] //only for HLSL code... but HLSL's content type is text by default..
    internal class HLSLHighlighterrProvider : IClassifierProvider
    {
        [Import]
        internal IClassificationTypeRegistryService ClassificationRegistry = null; //Set via MEF


        private HLSLDictionary _HLSLDictionary = null;
        private GLSLDictionary _GLSLDictionary = null;


        public IClassifier GetClassifier(ITextBuffer textBuffer)
        {

            string fp = HighlighterrUtility.GetBufferFileName(textBuffer);
            string ext = System.IO.Path.GetExtension(fp).ToLower();
            if (ext == ".hlsl")
            {
                EnsureHLSLDictionary();
                return textBuffer.Properties.GetOrCreateSingletonProperty<SLHighlighterr>(delegate { return new SLHighlighterr(ClassificationRegistry, _HLSLDictionary, textBuffer); });
            }
            else if ((ext == ".glsl") || (ext == ".vsh") || (ext == ".fsh") || (ext == "gsh"))
            {
                EnsureGLSLDictionary();
                return textBuffer.Properties.GetOrCreateSingletonProperty<SLHighlighterr>(delegate { return new SLHighlighterr(ClassificationRegistry, _GLSLDictionary, textBuffer); });
            }

            return null;
        }



        private void EnsureHLSLDictionary()
        {
            if (_HLSLDictionary == null)
            {
                _HLSLDictionary = new HLSLDictionary();
            }
        }
        private void EnsureGLSLDictionary()
        {
            if (_GLSLDictionary == null)
            {
                _GLSLDictionary = new GLSLDictionary();
            }
        }

    }

    enum SLIntellisenserType
    {
        None = 0,
        Keyword = 1,
        SpecialKeyword = 2,
        Type = 3,
        Enum = 4,
        Function = 5,
        Comment = 6,
    }
    class SLIntellisenserItem
    {
        public string Name;
        public SLIntellisenserType Type;
    }
    class SLUserTypeDictionary : Dictionary<string, SLIntellisenserItem>
    {
        public SLIntellisenserItem Add(string name, SLIntellisenserType type)
        {
            SLIntellisenserItem i = new SLIntellisenserItem();
            i.Name = name;
            i.Type = type;
            Add(name, i);
            return i;
        }
        public SLIntellisenserItem TryAdd(string name, SLIntellisenserType type)
        {
            if (!ContainsKey(name))
            {
                return Add(name, type);
            }
            return null;
        }
    }
    class SLLineHelper
    {

        private List<SLIntellisenserType> _LineEndStates = new List<SLIntellisenserType>();
        private bool _Inited = false;

        public void InitLines(ITextSnapshot snapshot)
        {
            if (_Inited) return;
            _Inited = true;

            _LineEndStates.Capacity = snapshot.LineCount + 1;

            foreach (ITextSnapshotLine line in snapshot.Lines)
            {
                _LineEndStates.Add(GetStateAtEndOfLine(line.LineNumber, line.GetText()));
            }

        }
        public SLIntellisenserType GetStateAtStartOfLine(int line)
        {
            SLIntellisenserType r = SLIntellisenserType.None;

            //return the end state of the previous line.
            int l = line - 1;
            if ((l >= 0) && (l < _LineEndStates.Count))
            {
                r = _LineEndStates[l];
            }

            return r;
        }
        public SLIntellisenserType GetStateAtEndOfLine(int line, string lineText)
        {
            SLIntellisenserType r = GetStateAtStartOfLine(line);
            char lastc = '\0';
            for (int i = 0; i < lineText.Length; i++)
            {
                char c = lineText[i];
                if ((lastc == '*') && (c == '/') && (r == SLIntellisenserType.Comment))
                {
                    r = SLIntellisenserType.None;
                }
                else if ((lastc == '/') && (c == '*') && (r == SLIntellisenserType.None))
                {
                    r = SLIntellisenserType.Comment;
                }
                lastc = c;
            }
            return r;
        }

        public void InsertLines(int startLine, int endLine)
        {
            int len = endLine - startLine;
            for (int i = 0; i < len; i++)
            {
                _LineEndStates.Insert(startLine, SLIntellisenserType.None);
            }
        }
        public void DeleteLines(int startLine, int endLine)
        {
            int len = endLine - startLine;
            _LineEndStates.RemoveRange(startLine, len);
        }
        public int RefreshState(SnapshotSpan span)
        {
            //return "new end line", ie last "valid" line in the span
            SLIntellisenserType cstate = SLIntellisenserType.None;
            ITextSnapshotLine containingLine = span.Start.GetContainingLine();
            int lineNumber = containingLine.LineNumber;
            int endLineNum = span.End.GetContainingLine().LineNumber;
            if (lineNumber >= 0)
            {
                cstate = GetStateAtStartOfLine(lineNumber);
            }
            bool flag = true;
            while (true)
            {
                if ((lineNumber > endLineNum) && ((lineNumber >= _LineEndStates.Count) || !flag))
                {
                    break;
                }
                string text = span.Snapshot.GetLineFromLineNumber(lineNumber).GetText();
                cstate = GetStateAtEndOfLine(lineNumber, text);
                SLIntellisenserType ostate = _LineEndStates[lineNumber];
                flag = (cstate != ostate);
                _LineEndStates[lineNumber] = cstate;
                lineNumber++;
            }
            return lineNumber - 1;
        }

    }
    class SLFileData
    {
        public SLUserTypeDictionary UserTypeDict = new SLUserTypeDictionary();
        public SLLineHelper LineHelper = new SLLineHelper();
    }
    class SLDictionary : Dictionary<string, SLIntellisenserItem>
    {
        //using an array will hopefully provide some sort of performance increase over iterating the collection of chars..
        public static string IdentifierChars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_#";
        public bool[] IsIdentifierChar = new bool[256];

        private Dictionary<string, SLFileData> SLFileDatas = new Dictionary<string, SLFileData>();

        public SLDictionary()
        {
            InitIdentifierChars();
        }

        private void InitIdentifierChars()
        {
            for (int i = 0; i < 256; i++)
            {
                IsIdentifierChar[i] = false;
                char c = (char)i;
                for (int j = 0; j < IdentifierChars.Length; j++)
                {
                    char ac = IdentifierChars[j];
                    if (c == ac)
                    {
                        IsIdentifierChar[i] = true;
                        break;
                    }
                }
            }
        }

        public void Add(string name, SLIntellisenserType type)
        {
            SLIntellisenserItem i = new SLIntellisenserItem();
            i.Name = name;
            i.Type = type;
            Add(name, i);
        }


        public SLFileData GetFileData(string fp)
        {
            SLFileData r = null;
            if (!SLFileDatas.TryGetValue(fp, out r))
            {
                r = new SLFileData();
                SLFileDatas.Add(fp, r);
            }
            return r;
        }
    }
    class SLHighlighterr : IClassifier
    {
        public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;

        private string _FilePath;
        private ITextBuffer _TextBuffer;
        private SLDictionary _SLDictionary;
        private SLFileData _FileData;
        private SLUserTypeDictionary _UserTypeDictionary;
        private SLLineHelper _LineHelper;

        private IClassificationType _ClassificationSomething;//only used as a fallback...
        private IClassificationType _ClassificationKeyword;
        private IClassificationType _ClassificationType;
        private IClassificationType _ClassificationEnum;
        private IClassificationType _ClassificationFunction;
        private IClassificationType _ClassificationComment;

        public SLHighlighterr(IClassificationTypeRegistryService registry, SLDictionary dict, ITextBuffer buffer)
        {
            _SLDictionary = dict;
            _TextBuffer = buffer;
            _TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
            _FilePath = HighlighterrUtility.GetBufferFileName(buffer);
            _FileData = dict.GetFileData(_FilePath);
            _UserTypeDictionary = _FileData.UserTypeDict;
            _LineHelper = _FileData.LineHelper;

            _ClassificationSomething = registry.GetClassificationType("HighlighterrSomething");
            _ClassificationKeyword = registry.GetClassificationType("Keyword");
            _ClassificationType = registry.GetClassificationType("HighlighterrType");
            _ClassificationEnum = registry.GetClassificationType("HighlighterrEnum");
            _ClassificationFunction = registry.GetClassificationType("HighlighterrFunction");
            _ClassificationComment = registry.GetClassificationType("Comment");
        }
        ~SLHighlighterr()
        {
            if (_TextBuffer != null)
            {
                //doesn't seem to get disposed in an orderly fashion.. darn gc!
                _TextBuffer.Changed -= new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
                _TextBuffer.Properties.RemoveProperty(typeof(SLHighlighterr));
                _TextBuffer = null;
            }
       }

        private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
        {
            if(e.Changes.Count>0)
            {
                int oldStartLine = e.Before.GetLineNumberFromPosition(e.Changes[0].OldPosition);
                int newEndLine = 0;

                foreach (ITextChange tc in e.Changes)
                {
                    int startLine = e.After.GetLineNumberFromPosition(tc.NewPosition);
                    if (tc.LineCountDelta < 0)
                    {
                        _LineHelper.DeleteLines(startLine, startLine + (-tc.LineCountDelta));
                    }
                    else if (tc.LineCountDelta > 0)
                    {
                        _LineHelper.InsertLines(startLine, startLine + tc.LineCountDelta);
                    }
                    newEndLine = e.After.GetLineNumberFromPosition(tc.NewEnd);
                }

                int start = e.After.GetLineFromLineNumber(oldStartLine).Start;
                int length = e.After.GetLineFromLineNumber(newEndLine).End - start;
                SnapshotSpan ss = new SnapshotSpan(e.After, start, length);
                int endLine = _LineHelper.RefreshState(ss);
                int lineLen = e.After.GetLineFromLineNumber(endLine).End - start;
                SnapshotSpan changeSpan = new SnapshotSpan(e.After, start, lineLen);
                ClassificationChangedEventArgs arg = new ClassificationChangedEventArgs(changeSpan);
                if (ClassificationChanged != null)
                {
                    ClassificationChanged(this, arg);
                }
            }
        }

        public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
        {
            List<ClassificationSpan> list = new List<ClassificationSpan>();

            _LineHelper.InitLines(span.Snapshot);

            int startLine = span.Snapshot.GetLineNumberFromPosition(span.Start.Position);
            int endLine = span.Snapshot.GetLineNumberFromPosition(span.End.Position - 1);
            int curLine = startLine;
            if (startLine <= endLine)
            {
                do
                {
                    ITextSnapshotLine line = span.Snapshot.GetLineFromLineNumber(curLine);
                    if (line != null)
                    {
                        list.AddRange(GetClassificationsForLine(line.ExtentIncludingLineBreak, curLine));
                    }
                    curLine++;
                }
                while (curLine <= endLine);

            }

            return list;
        }

        public List<ClassificationSpan> GetClassificationsForLine(SnapshotSpan lineSpan, int lineNumber)
        {
            List<ClassificationSpan> list = new List<ClassificationSpan>();

            if (lineSpan.Length > 0)
            {
                SLIntellisenserType startState = _LineHelper.GetStateAtStartOfLine(lineNumber);
                string text = lineSpan.GetText();
                int startpos = lineSpan.Start.Position;
                ITextSnapshot ss = lineSpan.Snapshot;

                string lastword = string.Empty;
                bool inword = false;
                bool wasinword = false;
                int wordstart = 0;
                bool instring = false;
                char stringterminator = '"';
                bool incomment = false;//this handles double-slash comments
                bool inmultiline = startState == SLIntellisenserType.Comment;//this is for handling /* */ comments
                bool commentstart = false;
                int commentstarti = 0;
                int multilinestarti = 0;


                char lastc = '\0';
                for (int i = 0; i < text.Length; i++)
                {
                    char c = text[i];
                    int cpos = startpos + i;
                    int ic = (int)c;
                    wasinword = inword;
                    inword = false;

                    if (c == '/' && !instring)
                    {
                        if (commentstart)
                        {
                            incomment = true;
                            commentstarti = i - 1;
                        }
                        commentstart = !incomment;
                        if (lastc == '*' && inmultiline)
                        {
                            //end of a multiline comment
                            inmultiline = false;
                            int len = i - multilinestarti;
                            int spos = cpos - len;
                            AddClassification(ss, spos, len + 1, SLIntellisenserType.Comment, list);
                        }
                    }
                    else
                    {
                        if (c == '*' && !instring)
                        {
                            if (commentstart && !incomment)
                            {
                                //start of a multiline comment...
                                inmultiline = true;
                                multilinestarti = i - 1;
                            }
                        }
                        else
                        {
                            if (!inmultiline && !incomment)
                            {
                                if (instring)
                                {
                                    if (c == stringterminator)//endstring if found terminator
                                    {
                                        instring = false;
                                    }
                                }
                                else
                                {
                                    if (c == '"')
                                    {
                                        instring = true;
                                        stringterminator = c;
                                    }
                                    else if (c == '\'')
                                    {
                                        instring = true;
                                        stringterminator = c;
                                    }
                                }
                            }
                        }
                        commentstart = false; //no comment..
                    }
                    if (c == '\r' || c == '\n')//endofline, not in single line comment anymore
                    {
                        if (incomment)
                        {
                            int clen = i - commentstarti;
                            AddClassification(ss, startpos + commentstarti, clen, SLIntellisenserType.Comment, list);
                        }
                        commentstart = false;
                        incomment = false;
                    }

                    if (!incomment && !inmultiline && !instring)
                    {
                        bool islastchar = (i + 1) == text.Length;
                        if (ic < 256)
                        {
                            inword = _SLDictionary.IsIdentifierChar[ic]; //quickly determine if this char is part of a word
                        }
                        if (inword && !wasinword)
                        {
                            wordstart = i; //last char wasn't an identifier char, so a word just started.
                        }
                        else if (wasinword && (!inword || islastchar)) //this char isn't an identifier, but the last one was, so a word just ended...
                        {
                            int wordlength = i - wordstart;
                            if (islastchar) wordlength++;
                            string word = text.Substring(wordstart, wordlength);
                            SLIntellisenserItem item = null;
                            _SLDictionary.TryGetValue(word, out item);
                            if (item == null) //try lowercase version of the word, if its a keyword its valid
                            {
                                string lword = word.ToLower();
                                _SLDictionary.TryGetValue(lword, out item);
                                if (item != null)
                                {
                                    if ((item.Type != SLIntellisenserType.Keyword) && (item.Type != SLIntellisenserType.SpecialKeyword))
                                    {
                                        item = null;//don't return anything but keywords that matched lowercase second time round
                                    }
                                }
                            }
                            if (item == null) //check for user types, and add user types..
                            {
                                if ((lastword == "struct") || (lastword == "class"))
                                {
                                    _UserTypeDictionary.TryAdd(word, SLIntellisenserType.Type);
                                }
                                _UserTypeDictionary.TryGetValue(word, out item);
                            }
                            if (item != null)
                            {
                                AddClassification(ss, startpos + wordstart, wordlength, item.Type, list);
                            }
                            lastword = word;
                        }

                    }


                    lastc = c;
                }

                if (inmultiline)//handles any multiline comments that start on this line and continue..
                {
                    int mllen = text.Length - multilinestarti;
                    AddClassification(ss, startpos + multilinestarti, mllen, SLIntellisenserType.Comment, list);
                }


            }

            return list;
        }

        private IClassificationType GetClassificationType(SLIntellisenserType t)
        {
            IClassificationType r = null;
            switch (t)
            {
                case SLIntellisenserType.Keyword:
                    r = _ClassificationKeyword;
                    break;
                case SLIntellisenserType.SpecialKeyword:
                    r = _ClassificationType;//show these as types
                    break;
                case SLIntellisenserType.Type:
                    r = _ClassificationType;
                    break;
                case SLIntellisenserType.Enum:
                    r = _ClassificationEnum;
                    break;
                case SLIntellisenserType.Function:
                    r = _ClassificationFunction;
                    break;
                case SLIntellisenserType.Comment:
                    r = _ClassificationComment;
                    break;
            }
            return r;
        }

        private void AddClassification(ITextSnapshot snapshot, int position, int length, SLIntellisenserType type, List<ClassificationSpan> list)
        {
            IClassificationType ct = GetClassificationType(type);
            if (ct != null)
            {
                list.Add(new ClassificationSpan(new SnapshotSpan(snapshot, position, length), ct));
            }
        }
    }

    class HLSLDictionary : SLDictionary
    {
        public HLSLDictionary()
        {
            SLIntellisenserType k = SLIntellisenserType.Keyword;
            SLIntellisenserType sk = SLIntellisenserType.SpecialKeyword;
            SLIntellisenserType t = SLIntellisenserType.Type;
            SLIntellisenserType e = SLIntellisenserType.Enum;
            SLIntellisenserType f = SLIntellisenserType.Function;

            #region HLSL preprocessor directives

            Add("#define", k);
            Add("#elif", k);
            Add("#else", k);
            Add("#endif", k);
            Add("#error", k);
            Add("#if", k);
            Add("#ifdef", k);
            Add("#ifndef", k);
            Add("#include", k);
            Add("#line", k);
            Add("#pragma", k);
            Add("#undef", k);

            #endregion

            #region HLSL profiles

            Add("vs_1_1", e);
            Add("ps_2_0", e);
            Add("vs_2_0", e);
            Add("ps_2_x", e);
            Add("vs_2_x", e);
            Add("ps_3_0", e);
            Add("vs_3_0", e);
            Add("gs_4_0", e);
            Add("ps_4_0", e);
            Add("vs_4_0", e);
            Add("gs_4_1", e);
            Add("ps_4_1", e);
            Add("vs_4_1", e);
            Add("cs_4_0", e);
            Add("cs_4_1", e);
            Add("cs_5_0", e);
            Add("ds_5_0", e);
            Add("gs_5_0", e);
            Add("hs_5_0", e);
            Add("ps_5_0", e);
            Add("vs_5_0", e);

            #endregion

            #region HLSL keywords

            Add("blendstate", sk);
            Add("bool", k);
            Add("break", k);
            Add("buffer", sk);
            Add("cbuffer", sk);
            Add("class", k);
            Add("compile", k);
            Add("const", k);
            Add("continue", k);
            Add("depthstencilstate", sk);
            Add("depthstencilview", sk);
            Add("discard", k);
            Add("do", k);
            Add("double", k);
            Add("else", k);
            Add("extern", k);
            Add("false", k);
            Add("for", k);
            Add("geometryshader", sk);
            Add("groupshared", k);
            Add("half", k);
            Add("if", k);
            Add("in", k);
            Add("inline", k);
            Add("inout", k);
            Add("int", k);
            Add("interface", k);
            Add("matrix", k);
            Add("namespace", k);
            Add("nointerpolation", k);
            Add("out", k);
            Add("pass", k);
            Add("pixelshader", sk);
            Add("precise", k);
            Add("rasterizerstate", sk);
            Add("rendertargetview", sk);
            Add("return", k);
            Add("register", k);
            Add("sampler", sk);
            Add("sampler1d", sk);
            Add("sampler2d", sk);
            Add("sampler3d", sk);
            Add("samplercube", sk);
            Add("sampler_state", sk);
            Add("samplerstate", sk);
            Add("samplercomparisonstate", sk);
            Add("shared", k);
            Add("stateblock", sk);
            Add("stateblock_state", sk);
            Add("static", k);
            Add("string", k);
            Add("struct", k);
            Add("switch", k);
            Add("tbuffer", sk);
            Add("technique", k);
            Add("technique10", k);
            Add("texture", t);
            Add("texture1d", sk);
            Add("texture1darray", sk);
            Add("texture2d", sk);
            Add("texture2darray", sk);
            Add("texture2dms", sk);
            Add("texture2dmsarray", sk);
            Add("texture3d", sk);
            Add("texturecube", sk);
            Add("texturecubearray", sk);
            Add("true", k);
            Add("typedef", k);
            Add("uniform", k);
            Add("uint", k);
            Add("ulong", k);
            Add("vector", k);
            Add("vertexshader", sk);
            Add("void", k);
            Add("volatile", k);
            Add("while", k);

            Add("object", k);
            Add("scalar", k);

            Add("float", k);
            Add("float2", k);
            Add("float3", k);
            Add("float4", k);
            Add("float2x2", k);
            Add("float3x3", k);
            Add("float4x4", k);

            #endregion

            #region HLSL reserved words

            Add("auto", k);
            Add("case", k);
            Add("catch", k);
            Add("char", k);
            Add("const_cast", k);
            Add("default", k);
            Add("delete", k);
            Add("dynamic_cast", k);
            Add("enum", k);
            Add("explicit", k);
            Add("friend", k);
            Add("goto", k);
            Add("long", k);
            Add("mutable", k);
            Add("new", k);
            Add("operator", k);
            Add("private", k);
            Add("protected", k);
            Add("public", k);
            Add("reinterpret_cast", k);
            Add("short", k);
            Add("signed", k);
            Add("sizeof", k);
            Add("static_cast", k);
            Add("template", k);
            Add("this", k);
            Add("throw", k);
            Add("try", k);
            Add("typename", k);
            Add("union", k);
            Add("unsigned", k);
            Add("using", k);
            Add("virtual", k);

            #endregion

            #region "enumy thingys." ie. standard semantics..

            // should really be more like user types, except maybe SV_TARGET and SV_POSITION...

            Add("SV_TARGET", e);
            Add("SV_POSITION", e);
            Add("SV_DEPTH", e);
            Add("SV_VERTEXID", e);
            Add("POSITION", e);
            Add("NORMAL", e);
            Add("COLOR", e);
            Add("TEXCOORD0", e);
            Add("TEXCOORD1", e);
            Add("TEXCOORD2", e);
            Add("TEXCOORD3", e);
            Add("TEXCOORD4", e);
            Add("TEXCOORD5", e);
            Add("TEXCOORD6", e);
            Add("TEXCOORD7", e);
            Add("TEXCOORD8", e);
            Add("TEXCOORD9", e);
            Add("TEXCOORD10", e);
            Add("TEXCOORD11", e);
            Add("TEXCOORD12", e);
            Add("TEXCOORD13", e);
            Add("TEXCOORD14", e);
            Add("TEXCOORD15", e);

            #endregion


            #region HLSL intrinsic functions....

            Add("abs", f);
            Add("acos", f);
            Add("all", f);
            Add("AllMemoryBarrier", f);
            Add("AllMemoryBarrierWithGroupSync", f);
            Add("any", f);
            Add("asdouble", f);
            Add("asfloat", f);
            Add("asin", f);
            Add("asint", f);
            Add("asuint", f);
            Add("atan", f);
            Add("atan2", f);
            Add("ceil", f);
            Add("clamp", f);
            Add("clip", f);
            Add("cos", f);
            Add("cosh", f);
            Add("countbits", f);
            Add("cross", f);
            Add("D3DCOLORtoUBYTE4", f);
            Add("ddx", f);
            Add("ddx_coarse", f);
            Add("ddx_fine", f);
            Add("ddy", f);
            Add("ddy_coarse", f);
            Add("ddy_fine", f);
            Add("degrees", f);
            Add("determinant", f);
            Add("DeviceMemoryBarrier", f);
            Add("DeviceMemoryBarrierWithGroupSync", f);
            Add("distance", f);
            Add("dot", f);
            Add("dst", f);
            Add("EvaluateAttributeAtCentroid", f);
            Add("EvaluateAttributeAtSample", f);
            Add("EvaluateAttributeSnapped", f);
            Add("exp", f);
            Add("exp2", f);
            Add("f16tof32", f);
            Add("f32tof16", f);
            Add("faceforward", f);
            Add("firstbithigh", f);
            Add("firstbitlow", f);
            Add("floor", f);
            Add("fmod", f);
            Add("frac", f);
            Add("frexp", f);
            Add("fwidth", f);
            Add("GetRenderTargetSampleCount", f);
            Add("GetRenderTargetSamplePosition", f);
            Add("GroupMemoryBarrier", f);
            Add("GroupMemoryBarrierWithGroupSync", f);
            Add("InterlockedAdd", f);
            Add("InterlockedAnd", f);
            Add("InterlockedCompareExchange", f);
            Add("InterlockedCompareStore", f);
            Add("InterlockedExchange", f);
            Add("InterlockedMax", f);
            Add("InterlockedMin", f);
            Add("InterlockedOr", f);
            Add("InterlockedXor", f);
            Add("isfinite", f);
            Add("isinf", f);
            Add("isnan", f);
            Add("ldexp", f);
            Add("length", f);
            Add("lerp", f);
            Add("lit", f);
            Add("log", f);
            Add("log10", f);
            Add("log2", f);
            Add("mad", f);
            Add("max", f);
            Add("min", f);
            Add("modf", f);
            Add("mul", f);
            Add("noise", f);
            Add("normalize", f);
            Add("pow", f);
            Add("Process2DQuadTessFactorsAvg", f);
            Add("Process2DQuadTessFactorsMax", f);
            Add("Process2DQuadTessFactorsMin", f);
            Add("ProcessIsolineTessFactors", f);
            Add("ProcessQuadTessFactorsAvg", f);
            Add("ProcessQuadTessFactorsMax", f);
            Add("ProcessQuadTessFactorsMin", f);
            Add("ProcessTriTessFactorsAvg", f);
            Add("ProcessTriTessFactorsMax", f);
            Add("ProcessTriTessFactorsMin", f);
            Add("radians", f);
            Add("rcp", f);
            Add("reflect", f);
            Add("refract", f);
            Add("reversebits", f);
            Add("round", f);
            Add("rsqrt", f);
            Add("saturate", f);
            Add("sign", f);
            Add("sin", f);
            Add("sincos", f);
            Add("sinh", f);
            Add("smoothstep", f);
            Add("sqrt", f);
            Add("step", f);
            Add("tan", f);
            Add("tanh", f);
            Add("tex1D", f);
            Add("tex1Dbias", f);
            Add("tex1Dgrad", f);
            Add("tex1Dlod", f);
            Add("tex1Dproj", f);
            Add("tex2D", f);
            Add("tex2Dbias", f);
            Add("tex2Dgrad", f);
            Add("tex2Dlod", f);
            Add("tex2Dproj", f);
            Add("tex3D", f);
            Add("tex3Dbias", f);
            Add("tex3Dgrad", f);
            Add("tex3Dlod", f);
            Add("tex3Dproj", f);
            Add("texCUBE", f);
            Add("texCUBEbias", f);
            Add("texCUBEgrad", f);
            Add("texCUBElod", f);
            Add("texCUBEproj", f);
            Add("transpose", f);
            Add("trunc", f);

            #endregion

            #region SM 4.0 attributes

            Add("maxvertexcount", sk);

            #endregion

            #region SM 5.0 attributes

            Add("domain", sk);
            Add("earlydepthstencil", sk);
            Add("instance", sk);
            Add("maxtessfactor", sk);
            Add("numthreads", sk);
            Add("outputcontrolpoints", sk);
            Add("outputtopology", sk);
            Add("partitioning", sk);
            Add("patchconstantfunc", sk);

            #endregion

            #region SM 5.0 Objects

            Add("AppendStructuredBuffer", t);
            Add("Buffer", t);
            Add("ByteAddressBuffer", t);
            Add("ConsumeStructuredBuffer", t);
            Add("InputPatch", t);
            Add("OutputPatch", t);
            Add("RWBuffer", t);
            Add("RWByteAddressBuffer", t);
            Add("RWStructuredBuffer", t);
            Add("RWTexture1D", t);
            Add("RWTexture1DArray", t);
            Add("RWTexture2D", t);
            Add("RWTexture2DArray", t);
            Add("RWTexture3D", t);
            Add("StructuredBuffer", t);
            Add("Texture1D", t);
            Add("Texture1DArray", t);
            Add("Texture2D", t);
            Add("Texture2DArray", t);
            Add("Texture2DMS", t);
            Add("Texture2DMSArray", t);
            Add("Texture3D", t);

            #endregion

            #region SM 5.0 System Values

            Add("SV_DispatchThreadID", e);
            Add("SV_DomainLocation", e);
            Add("SV_GroupID", e);
            Add("SV_GroupIndex", e);
            Add("SV_GroupThreadID", e);
            Add("SV_GSInstanceID", e);
            Add("SV_InsideTessFactor", e);
            Add("SV_OutputControlPointID", e);
            Add("SV_TessFactor", e);

            #endregion


            #region texture sampler enum values

            Add("MIN_MAG_MIP_POINT", e);
            Add("MIN_MAG_POINT_MIP_LINEAR", e);
            Add("MIN_POINT_MAG_LINEAR_MIP_POINT", e);
            Add("MIN_POINT_MAG_MIP_LINEAR", e);
            Add("MIN_LINEAR_MAG_MIP_POINT", e);
            Add("MIN_LINEAR_MAG_POINT_MIP_LINEAR", e);
            Add("MIN_MAG_LINEAR_MIP_POINT", e);
            Add("MIN_MAG_MIP_LINEAR", e);
            Add("ANISOTROPIC", e);
            Add("COMPARISON_MIN_MAG_MIP_POINT", e);
            Add("COMPARISON_MIN_MAG_POINT_MIP_LINEAR", e);
            Add("COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT", e);
            Add("COMPARISON_MIN_POINT_MAG_MIP_LINEAR", e);
            Add("COMPARISON_MIN_LINEAR_MAG_MIP_POINT", e);
            Add("COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR", e);
            Add("COMPARISON_MIN_MAG_LINEAR_MIP_POINT", e);
            Add("COMPARISON_MIN_MAG_MIP_LINEAR", e);
            Add("COMPARISON_ANISOTROPIC", e);
            Add("TEXT_1BIT", e);

            Add("WRAP", e);
            Add("MIRROR", e);
            Add("CLAMP", e);
            Add("BORDER", e);
            Add("MIRROR_ONCE", e);

            Add("NEVER", e);
            Add("LESS", e);
            Add("EQUAL", e);
            Add("LESS_EQUAL", e);
            Add("GREATER", e);
            Add("NOT_EQUAL", e);
            Add("GREATER_EQUAL", e);
            Add("ALWAYS", e);


            #endregion

        }
    }

    class GLSLDictionary : SLDictionary
    {
        public GLSLDictionary()
        {
            SLIntellisenserType k = SLIntellisenserType.Keyword;
            SLIntellisenserType t = SLIntellisenserType.Type;
            SLIntellisenserType e = SLIntellisenserType.Enum;
            SLIntellisenserType f = SLIntellisenserType.Function;
            //SLIntellisenserType sk = SLIntellisenserType.SpecialKeyword;

            #region GLSL functions

            Add("main", f);
            Add("abs", f);
            Add("acos", f);
            Add("all", f);
            Add("any", f);
            Add("asin", f);
            Add("atan", f);
            Add("ceil", f);
            Add("clamp", f);
            Add("cos", f);
            Add("cross", f);
            Add("dFdx", f);
            Add("dFdy", f);
            Add("degrees", f);
            Add("distance", f);
            Add("dot", f);
            Add("equal", f);
            Add("exp", f);
            Add("exp2", f);
            Add("faceforward", f);
            Add("floor", f);
            Add("fract", f);
            Add("ftransform", f);
            Add("fwidth", f);
            Add("greaterThan", f);
            Add("greaterThanEqual", f);
            Add("inversesqrt", f);
            Add("length", f);
            Add("lessThan", f);
            Add("lessThanEqual", f);
            Add("log", f);
            Add("log2", f);
            Add("matrixCompMult", f);
            Add("max", f);
            Add("min", f);
            Add("mix", f);
            Add("mod", f);
            Add("noise1", f);
            Add("noise2", f);
            Add("noise3", f);
            Add("noise4", f);
            Add("normalize", f);
            Add("not", f);
            Add("notEqual", f);
            Add("pow", f);
            Add("radians", f);
            Add("reflect", f);
            Add("refract", f);
            Add("shadow1D", f);
            Add("shadow1DLod", f);
            Add("shadow1DProj", f);
            Add("shadow1DProjLod", f);
            Add("shadow2D", f);
            Add("shadow2DLod", f);
            Add("shadow2DProj", f);
            Add("shadow2DProjLod", f);
            Add("sign", f);
            Add("sin", f);
            Add("smoothstep", f);
            Add("sqrt", f);
            Add("step", f);
            Add("tan", f);
            Add("texture1D", f);
            Add("texture1DLod", f);
            Add("texture1DProj", f);
            Add("texture1DProjLod", f);
            Add("texture2D", f);
            Add("texture2DLod", f);
            Add("texture2DProj", f);
            Add("texture2DProjLod", f);
            Add("texture3D", f);
            Add("texture3DLod", f);
            Add("texture3DProj", f);
            Add("texture3DProjLod", f);
            Add("textureCube", f);
            Add("textureCubeLod", f);

            #endregion

            #region GLSL keywords

            Add("attribute", k);
            Add("bool", k);
            Add("break", k);
            Add("bvec2", k);
            Add("bvec3", k);
            Add("bvec4", k);
            Add("const", k);
            Add("continue", k);
            Add("discard", k);
            Add("do", k);
            Add("else", k);
            Add("false", k);
            Add("float", k);
            Add("for", k);
            Add("if", k);
            Add("in", k);
            Add("inout", k);
            Add("int", k);
            Add("ivec2", k);
            Add("ivec3", k);
            Add("ivec4", k);
            Add("mat2", k);
            Add("mat3", k);
            Add("mat4", k);
            Add("out", k);
            Add("return", k);
            Add("true", k);
            Add("uniform", k);
            Add("varying", k);
            Add("vec2", k);
            Add("vec3", k);
            Add("vec4", k);
            Add("void", k);
            Add("while", k);
            Add("struct", k);


            Add("asm", k);
            Add("cast", k);
            Add("class", k);
            Add("default", k);
            Add("double", k);
            Add("dvec2", k);
            Add("dvec3", k);
            Add("dvec4", k);
            Add("enum", k);
            Add("extern", k);
            Add("external", k);
            Add("fixed", k);
            Add("fvec2", k);
            Add("fvec3", k);
            Add("fvec4", k);
            Add("goto", k);
            Add("half", k);
            Add("hvec2", k);
            Add("hvec3", k);
            Add("hvec4", k);
            Add("inline", k);
            Add("input", k);
            Add("interface", k);
            Add("long", k);
            Add("namespace", k);
            Add("noinline", k);
            Add("output", k);
            Add("packed", k);
            Add("public", k);
            Add("sampler2DRect", k);
            Add("sampler3DRect", k);
            Add("sampler3DRectShadow", k);
            Add("short", k);
            Add("sizeof", k);
            Add("static", k);
            Add("switch", k);
            Add("template", k);
            Add("this", k);
            Add("typedef", k);
            Add("union", k);
            Add("unsigned", k);
            Add("using", k);
            Add("volatile", k);

            Add("highp", k);
            Add("lowp", k);

            #endregion

            #region GLSL types

            Add("sampler1D", t);
            Add("sampler2D", t);
            Add("sampler3D", t);
            Add("samplerCube", t);
            Add("sampler1DShadow", t);
            Add("sampler2DShadow", t);

            #endregion

            #region GLSL things starting with "gl_"
            //couldn't decide what colour to make these - "Enum" seemed the nicest, although meaningless

            Add("gl_BackLightModelProduct", e);
            Add("gl_BackLightProduct", e);
            Add("gl_BackMaterial", e);
            Add("gl_ClipPlane", e);
            Add("gl_DepthRange", e);
            Add("gl_DepthRangeParameters", e);
            Add("gl_EyePlaneQ", e);
            Add("gl_EyePlaneR", e);
            Add("gl_EyePlaneS", e);
            Add("gl_EyePlaneT", e);
            Add("gl_Fog", e);
            Add("gl_FogParameters", e);
            Add("gl_FrontLightModelProduct", e);
            Add("gl_FrontLightProduct", e);
            Add("gl_FrontMaterial", e);
            Add("gl_LightModel", e);
            Add("gl_LightModelParameters", e);
            Add("gl_LightModelProducts", e);
            Add("gl_LightProducts", e);
            Add("gl_LightSource", e);
            Add("gl_LightSourceParameters", e);
            Add("gl_MaterialParameters", e);
            Add("gl_MaxClipPlanes", e);
            Add("gl_MaxCombinedTextureImageUnits", e);
            Add("gl_MaxDrawBuffers", e);
            Add("gl_MaxFragmentUniformComponents", e);
            Add("gl_MaxLights", e);
            Add("gl_MaxTextureCoords", e);
            Add("gl_MaxTextureImageUnits", e);
            Add("gl_MaxTextureUnits", e);
            Add("gl_MaxVaryingFloats", e);
            Add("gl_MaxVertexAttribs", e);
            Add("gl_MaxVertexTextureImageUnits", e);
            Add("gl_MaxVertexUniformComponents", e);
            Add("gl_ModelViewMatrix", e);
            Add("gl_ModelViewMatrixInverse", e);
            Add("gl_ModelViewMatrixInverseTranspose", e);
            Add("gl_ModelViewMatrixTranspose", e);
            Add("gl_ModelViewProjectionMatrix", e);
            Add("gl_ModelViewProjectionMatrixInverse", e);
            Add("gl_ModelViewProjectionMatrixInverseTranspose", e);
            Add("gl_ModelViewProjectionMatrixTranspose", e);
            Add("gl_NormalMatrix", e);
            Add("gl_NormalScale", e);
            Add("gl_ObjectPlaneQ", e);
            Add("gl_ObjectPlaneR", e);
            Add("gl_ObjectPlaneS", e);
            Add("gl_ObjectPlaneT", e);
            Add("gl_Point", e);
            Add("gl_PointParameters", e);
            Add("gl_ProjectionMatrix", e);
            Add("gl_ProjectionMatrixInverse", e);
            Add("gl_ProjectionMatrixInverseTranspose", e);
            Add("gl_ProjectionMatrixTranspose", e);
            Add("gl_TextureEnvColor", e);
            Add("gl_TextureMatrix", e);
            Add("gl_TextureMatrixInverse", e);
            Add("gl_TextureMatrixInverseTranspose", e);
            Add("gl_TextureMatrixTranspose", e);
            Add("gl_BackColor", e);
            Add("gl_BackSecondaryColor", e);
            Add("gl_ClipVertex", e);
            Add("gl_Color", e);
            Add("gl_FogCoord", e);
            Add("gl_FogFragCoord", e);
            Add("gl_FragColor", e);
            Add("gl_FragCoord", e);
            Add("gl_FragData", e);
            Add("gl_FragDepth", e);
            Add("gl_FrontColor", e);
            Add("gl_FrontFacing", e);
            Add("gl_FrontSecondaryColor", e);
            Add("gl_MultiTexCoord0", e);
            Add("gl_MultiTexCoord1", e);
            Add("gl_MultiTexCoord2", e);
            Add("gl_MultiTexCoord3", e);
            Add("gl_MultiTexCoord4", e);
            Add("gl_MultiTexCoord5", e);
            Add("gl_MultiTexCoord6", e);
            Add("gl_MultiTexCoord7", e);
            Add("gl_Normal", e);
            Add("gl_PointSize", e);
            Add("gl_Position", e);
            Add("gl_SecondaryColor", e);
            Add("gl_TexCoord", e);
            Add("gl_Vertex", e);

            #endregion

        }
    }

}
